/* Structures used in graph elaboration */

#ifndef GRAFI
#define GRAFI
#define AREAS_MAX_SIZE 10
#define MONOPOLYZE_FACTOR 20

#include <stdio.h>	/* The stdio header provides functions for performing input and output. */
#include <stdlib.h>	/* The stdlib header defines several general operation functions and macros. */
#include <string.h>	/* The string header provides manipulating strings functions */
#include <math.h>	/* The math header defines several mathematic functions. */
#include <time.h>	/* The time header provides several time and date functions . */
#include "_gl.h"
#include "elements.h"
#include "io_grid.h"

/* Grid areas */

void init_gl();

struct list_areas {
	long int area;
	struct list_areas* next;
	int counter;
};
typedef struct list_areas list_areas;
	
void push_area(list_areas** first,  int area );
	/* Pushed an area at the beginning of a stack */

int delete_area_from_list(list_areas** first,  int area );
	/* Deletes first area from the stack */
	
void assign_label_list_arcs( list_real_arcs* real_arcs);
	/*  For each arc it takes the node assigning them the "label" of the arc. 
	 *   In this case the "label" is the starting and end arc nodes which represent the limits */
	 
list_real_arcs* create_list_arcs( grid* gr, int level);
	/* Takes a node and visit all his neighbours in a wide visit.
	 *  Returns the number of real arcs and inserts in *rest_arcs all the arcs of  grid.
	 *  It is used to give the argument of assign_lael_list_arcs */
	 
int wide_visit( grid* gr, list_arcs** rest_arcs);
	/* Takes a node and visit alls his neighbours in a wide visit */
	/* Returns the number of real arcs and insert in *rest_arcs all the arcs of the grid */
	
void prepare_list_arcs(list_arcs* arcs);
	/* Takes all arcs and exchanges n1 node with n2 node if the coordinates of n1 are greater than n2.
	 * It is used to understand if there are two different cells linked by more than one arcs */

int compare_arcs(const arc* a1, const arc* a2);
	/* Function used to sort arcs*/

void create_path(grid* gr, node* n1, node* n2, int vert);
	/* Creates a path with all the neighbourhoods linking two nodes. "vert" is a boolean which indicates 
	 * if the path is in vertical direction or horizontal when the nodes are not straight, but now it isn't useful, only straight is used.
	 * It is used to create a new grid manually */

int is_neighbour( node* n1, node* n2);
	/* It verifies if n1 is neighbour of n2 (it is not important to demonstrate the viceversa because it is obvious */

int are_all_neighbours(list_nodes *list, node* n, int type);
	/* It verifies if all nodes of list are neighbours of n and of the same type.
	 * If type < 0 there isn't a check on node type */
	 
int is_free_cell( grid* gr, int x, int y);
	/* It verifies if an x,y cell in a grid is free */
	
int neighbours_number(node* n1);
	/* Returns the number of neighbours of the node n1 */
	
int verify_labels( node* n, list_nodes *nodes);
	/* Verifies if all nodes have one limit-node equal to n one.
	 * It is used to put a constraint in the moving of the nodes in the cell */
	 
int move_real_node(grid* gr, node* n, int x, int y);
	/* 
	Precondition:	
		1 - Node is real node
		2 - Cell (x, y) isn't the same cell of n
		3 - Cell (x, y) is a "near" n position
		4 - Destination cell (x,y) is free or contains nodes which are all not real nodes neighbours of n
		
	Postcondition:	
		1 - Creation of new bends or segments, each one for old neighbours of n (but not those in destination cell)
		1 or 2 - Movement of node n in destination cell ( delete from starting cell, insertion in destination cell )
		
		All these postconditions still consists in replacing/recreatings neighbourhoods
	*/	 
	
int move_bend(grid* gr, node* n, int x, int y);
	/* Precondition:
		1 - Node n is of type 1
		2 - Node n has two neighbours
		3 - One or both among the two neighbours is in destination cell (x, y)
		4 - The two neighbours and the node n form a rect angle or a skipnot
		
	   Postcondition:
	   	1.1 - Move the node n in "opposite" position
		1.2 - Skipnot is removed
	*/

int move_corner(grid* gr, node*n, int x, int y, int var_x, int var_y );
	/* Moves a bend in the opposite cell.
	*   It is used by move_bend (having the same precondition) in the case bend isn't part of skipnot .
	*   x e y are destination coords, var_x, var_y identifies which type of corner is:
	*   1,  1 North-West
	*-  1,  1 South-West
	*  -1, -1 South-East
	*   1, -1 North-East) */
	
int move_node(grid* gr, node* n, int x, int y);
	/* Moves a node (real or bend node) n in x, y destination cell */
	
void move_nodes(grid* gr, int x, int y, char* direction);
	/* Moves all nodes in x+var_x, y+var_y destination cell.
	 *  var_x, var_y are definied by direction ("Up", "Down", "Left", "Right") */

void move_row(grid * gr, int row, int new_row, int double_direction);
	/* Move all nodes of a row at new row.
	 *  If double direction is 1, it repeat the movement 
	 *  scanning row nodes in reversing order */

void move_column(grid* gr, int column, int new_column, int double_direction);
	/* Move all nodes of a column at new column.
	 *  If double direction is 1, it repeat the movement 
	 *  scanning column nodes in reversing order */

void move_to_column(grid* gr, int from_column, int to_column, int double_direction);
	/* Move all nodes towards to_row.
	 *   If double direction is 1, it repeat the movement 
	 *   scanning row nodes in reversing order */
	 
void move_to_row(grid* gr, int from_row, int to_row, int double_direction);
	/* Move all nodes towards to_column.
	 *   If double direction is 1, it repeat the movement 
	 *   scanning column nodes in reversing order */

int get_area( grid* gr, int* limits );
	/* Calculates area of a grid and returns row and column limits
	 *  where there are graph borders*/

int verify_same_position( node*n );
	/* Scans all neighbours and verifies if all ones are in the same position */
	
void retraction( grid* gr, node* n);
	/* If node n neighbours are all in the same position, it moves n towards neighbours position*/

int is_empty_row( grid* gr, int row );
	/* Verifies if a row has only empty cells */

int is_empty_column( grid* gr, int column );
	/* Verifies if a column has only empty cells */

int bends_number( grid* gr );
	/* Calculates bends in a grid */
	
int segments_length( list_real_arcs* real_arcs);
	/* Calculates length of arcs in a grid.
	 *  It needs real_arcs list */

int verify_monopolyze( list_areas* first_areas, int steps );
	/* Verifies if the area calculus outcomes the same value for MONOPOLYZE_FACTOR times*/

int update_area_stats( list_areas** first_areas,  int area_value );
 	/* Inserts area_value in list of areas which it must be used to verifies if the alghoritm is minimizing */
 
void elaborate_grid( grid* gr, config* cfg, stats* values );
	/* Minimizes grid using the preferred alghoritm and parameters described in config structure.
	 *  It updates values stats */
	 
void elaborate_each_grid(char* file_name, int lenstr, char* directory, char* directory_out, config* cfg, char* stats_file);
	/* Loads grid from file, elaborates it and updates stats  */

void elaborate_grids( char* directory, char* stats_file, config* cfg );
	/* Elaborates all grids file in directory with cfg configuration and updates stats_file */

void print_file( char* file_name );
	/* Prints a pdf graph file using gl2ps libraries  */
	
#endif
